package pers.mor.tomcat.http;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;

import javax.servlet.http.Cookie;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class Response extends BaseResponse {

    private StringWriter stringWriter;
    private PrintWriter writer;
    private String contentType;
    private String encoding;
    private byte[] body;
    private int status;
    private String redirectPath;
    private List<Cookie> cookieList;
    private CompressionConfig acceptCompression;
    private boolean useCompression;

    public Response() {
        this.stringWriter = new StringWriter();
        this.writer = new PrintWriter(this.stringWriter);
        this.cookieList = new ArrayList<>();
    }

    // 写入流中的内容只是内容，并不包含响应头信息。
    // 返回body用于后期拼接成完整的响应头和响应体。
    public byte[] getBody() {
        if (this.body == null) {
            String body = this.stringWriter.toString();
            byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
            return bytes;
        }
        return this.body;
    }

    public String getCookiesHeader() {
        List<Cookie> cookies = this.cookieList;
        if (cookies.size() == 0) {
            return "";
        }

        String pattern = "EEE, d MMM yyyy HH:mm:ss 'GMT'";
        SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.ENGLISH);

        StringBuffer cookieStr = new StringBuffer();

        for (Cookie cookie : cookies) {
            cookieStr.append("\r\n");
            cookieStr.append("Set-Cookie: ");
            String name = cookie.getName();
            String value = cookie.getValue();
            cookieStr.append(name + "=" + value + "; ");

            if (cookie.getMaxAge() != -1) {
                // cookie.getMaxAge()的默认值是-1，设置为0则代表浏览器关闭cookie也跟着销毁。
                // 不等于-1即代表被webapp应用主动设置过cookie的有效期。
                // 浏览器根据Expires这段内容处理cookie的保存时间。
                cookieStr.append("Expires=");
                Date now = new Date();
                Date expire = DateUtil.offset(now, DateField.SECOND, cookie.getMaxAge());
                cookieStr.append(sdf.format(expire));
                cookieStr.append("; ");
            }
            if (null != cookie.getPath()) {
                cookieStr.append("Path=" + cookie.getPath());
            } else {
                cookieStr.deleteCharAt(cookieStr.length() - 2);
            }
        }
        return cookieStr.toString();
    }

    public PrintWriter getWriter() {
        return writer;
    }

    @Override
    public String getCharacterEncoding() {
        return this.encoding;
    }

    @Override
    public void setCharacterEncoding(String s) {
        this.encoding = "charset=" + s;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }

    public String getContentType() {
        return contentType;
    }

    public void setBody(byte[] body) {
        this.body = body;
    }

    @Override
    public int getStatus() {
        return this.status;
    }

    @Override
    public void setStatus(int status) {
        this.status = status;
    }

    public String getRedirectPath() {
        return this.redirectPath;
    }

    @Override
    public void sendRedirect(String s) throws IOException {
        this.redirectPath = s;
    }

    public void addCookie(Cookie cookie) {
        this.cookieList.add(cookie);
    }

    public List<Cookie> getCookies() {
        return this.cookieList;
    }

    public void acceptCompression(CompressionConfig config) {
        boolean isAccept = config.isBrowserSupport();
        if (isAccept == false) {
            this.useCompression = false;
            return;
        } else {
            this.useCompression = true;
            CompressionConfig compression = new CompressionConfig(true);
            compression.setCompression(config.getCompression());
            compression.setCompressionMinSize(config.getCompressionMinSize());
            compression.setCompressableMimeType(config.getCompressableMimeType());
            compression.setNoCompressionUserAgents(config.getNoCompressionUserAgents());
            this.acceptCompression = compression;
        }
    }

    CompressionConfig compression() {
        return this.acceptCompression;
    }

    boolean isUseCompression(){
        return this.useCompression;
    }
}
